/**
 * 服务器应用核心配置文件
 * 功能：初始化Express应用，配置全局中间件、路由系统和错误处理机制
 */

// ======================== 核心模块导入 ========================
// 导入Express框架，用于创建Web服务器
const express = require('express');
// 导入cors中间件，处理跨域资源共享（解决前端跨域请求限制）
const cors = require('cors');
// 导入helmet中间件，增强HTTP头安全性（防御XSS、点击劫持等攻击）
const helmet = require('helmet');
// 导入morgan中间件，记录HTTP请求日志（便于调试和监控）
const morgan = require('morgan');
// 导入dotenv，加载.env文件中的环境变量（如端口号、数据库地址等）
require('dotenv').config();

// ======================== 业务路由导入 ========================
// 导入认证相关路由（登录、注册、用户信息）
const authRoutes = require('./routes/auth');
// 导入设备模板相关路由(CRUD操作)
const equipmentTemplateRoutes = require('./routes/equipmentTemplate');

// ======================== 应用初始化 ========================
// 创建Express应用实例 - 服务器核心对象
const app = express();

// ======================== 全局中间件配置 ========================
// 中间件执行顺序：按代码顺序执行，请求到达接口前会依次经过这些处理

/**
 * 跨域资源共享(CORS)配置
 * 安全说明：
 *   - 开发环境：允许所有来源(*)方便调试
 *   - 生产环境：严格限制来源，仅允许信任的前端域名访问API
 *   这是防止CSRF攻击和未授权跨域请求的重要措施
 */
const corsOptions = {
  // 允许的请求来源
  origin: process.env.NODE_ENV === 'production' ? process.env.CORS_ORIGIN : '*',

  // 允许的HTTP方法
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],

  // 允许的请求头
  allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],

  // 允许前端访问的响应头
  exposedHeaders: ['X-Total-Count', 'X-Pagination'],

  // 是否允许携带凭证（如cookies、HTTP认证信息）
  credentials: true,

  // 预检请求(OPTIONS)的缓存时间（秒）
  // 减少OPTIONS请求次数，提高性能
  maxAge: 86400, // 24小时
};
app.use(cors(corsOptions));

/**
 * 安全HTTP头配置
 * Helmet会自动设置以下安全相关的HTTP头：
 *   - Content-Security-Policy: 限制资源加载来源，防御XSS
 *   - X-XSS-Protection: 启用浏览器内置的XSS过滤器
 *   - X-Content-Type-Options: 防止MIME类型嗅探
 *   - X-Frame-Options: 防止点击劫持
 *   - Strict-Transport-Security: 强制使用HTTPS
 *   - 以及其他共14种安全头配置
 */
app.use(helmet());

/**
 * 请求日志配置
 * 根据环境选择不同的日志格式：
 *   - 开发环境：简洁的dev格式，便于调试
 *   - 生产环境：详细的combined格式，便于分析和审计
 */
if (process.env.NODE_ENV === 'production') {
  // 生产环境日志格式：包含完整的请求信息
  // 格式：:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"
  app.use(morgan('combined'));
} else {
  // 开发环境日志格式：简洁明了
  // 格式：:method :url :status :response-time ms - :res[content-length]
  app.use(morgan('dev'));
}

/**
 * JSON请求体解析
 * 功能：将请求中的JSON数据解析为req.body对象
 * 安全配置：
 *   - limit: 限制最大请求体大小为10kb，防止大型请求攻击
 *   - strict: 仅解析数组和对象，拒绝其他类型
 */
app.use(
  express.json({
    limit: '10kb', // 10kb是大多数API的合理上限，可根据业务调整
    strict: true, // 严格模式，只接受数组和对象
  }),
);

/**
 * 表单数据解析
 * 功能：解析application/x-www-form-urlencoded格式的请求体
 * 配置说明：
 *   - extended: true 使用qs库解析，支持嵌套对象
 *   - limit: 同样限制为10kb，保持与JSON解析一致的安全策略
 */
app.use(
  express.urlencoded({
    extended: true, // 支持嵌套对象
    limit: '10kb', // 安全限制
  }),
);

// ======================== 业务路由配置 ========================
/**
 * 认证相关路由
 * 基础路径：/api/auth
 * 完整接口列表：
 *   - POST /api/auth/register - 用户注册
 *   - POST /api/auth/login - 用户登录
 *   - GET /api/auth/me - 获取当前登录用户信息
 */
app.use('/api/auth', authRoutes);

/**
 * 设备模板相关路由
 * 完整接口列表：
 *   - GET /api/equipment-templates/all - 获取所有设备模板
 *   - GET /api/equipment-templates - 获取分页设备模板列表
 *   - POST /api/equipment-templates - 创建设备模板
 *   - PUT /api/equipment-templates/:id - 更新设备模板
 *   - DELETE /api/equipment-templates/:id - 删除设备模板
 *   - GET /api/equipment-templates/:id - 获取设备模板详情
 */
app.use('/api/equipment-templates', equipmentTemplateRoutes);

/**
 * 根路由（健康检查路由）
 * 用途：
 *   1. 验证服务器是否正常运行
 *   2. 部署后的基础健康检查
 *   3. 负载均衡器状态检测
 * 返回标准化的成功响应，包含环境信息和时间戳
 */
app.get('/', (req, res) => {
  res.status(200).json({
    status: 'success',
    message: '微著巡音 API 服务正常运行中',
    timestamp: new Date().toISOString(),
    environment: process.env.NODE_ENV,
    version: '1.0.0',
  });
});

/**
 * 404路由处理中间件
 * 作用：处理所有未匹配到已定义路由的请求
 * 位置：必须放在所有业务路由之后，才能正确捕获未匹配的请求
 * 返回标准化的404响应，包含请求方法和路径信息
 */
app.use((req, res, next) => {
  // 动态收集所有可用路由的函数
  const collectRoutes = (routerStack, basePath = '') => {
    const routes = []; // 用于存储收集到的路由

    // 遍历路由栈中的每一层
    routerStack.forEach((layer) => {
      // 处理子路由（路由嵌套情况）
      if (layer.handle.stack) {
        // 计算子路由的基础路径
        // layer.route?.path 处理有明确路径的路由
        // layer.regexp.source 处理通过use挂载的路由（如app.use('/api', router)）
        const newBasePath = basePath + (layer.route ? layer.route.path : layer.regexp.source);
        // 递归收集子路由，并将结果合并到当前路由数组
        routes.push(...collectRoutes(layer.handle.stack, newBasePath));
      }

      // 处理单个路由（非嵌套的路由）
      if (layer.route) {
        // 提取该路由支持的所有HTTP方法（如GET、POST等）
        const methods = Object.keys(layer.route.methods)
          .map((method) => method.toUpperCase()) // 转换为大写形式
          .join(', '); // 用逗号拼接成字符串

        // 计算完整的路由路径（基础路径 + 路由自身路径）
        const fullPath = basePath + layer.route.path;
        // 将格式化后的路由信息添加到数组（格式："方法 路径"）
        routes.push(`${methods} ${fullPath}`);
      }
    });

    return routes; // 返回收集到的所有路由
  };

  // 从应用的根路由栈开始收集所有路由
  const availableRoutes = collectRoutes(app._router.stack);

  // 返回404响应
  res.status(404).json({
    status: 'fail',
    message: `请求的资源不存在: ${req.method} ${req.originalUrl}`,
    // 开发环境下添加调试信息（使用扩展运算符条件添加属性）
    ...(process.env.NODE_ENV === 'development' && {
      hint: '请检查请求方法和路径是否正确',
      availableRoutes: availableRoutes.sort(), // 排序后展示，更易读
    }),
  });
});

// ======================== 全局错误处理中间件 ========================
/**
 * 全局错误处理中间件
 * 特点：必须包含4个参数 (err, req, res, next)，Express才会识别为错误处理中间件
 * 功能：统一处理应用中所有同步和异步操作抛出的错误
 */
app.use((err, req, res, next) => {
  // 1. 记录错误详情（生产环境可写入日志文件）
  console.error(`[${new Date().toISOString()}] 错误发生:`, err.stack);

  // 2. 确定错误状态码和状态类型
  // 优先使用错误对象自带的状态码，否则默认500（服务器内部错误）
  const statusCode = err.statusCode || 500;
  // 状态类型：客户端错误为"fail"，服务器错误为"error"
  const status = err.status || 'error';
  // 错误信息：使用错误对象的message，否则使用默认信息
  const message = err.message || '服务器内部发生错误';

  // 3. 构建响应对象
  const errorResponse = {
    status,
    message,
    timestamp: new Date().toISOString(),
    path: req.path,
    method: req.method,
  };

  // 4. 开发环境添加详细调试信息
  if (process.env.NODE_ENV === 'development') {
    errorResponse.stack = err.stack; // 错误堆栈信息
    errorResponse.error = err; // 完整错误对象
  }

  // 5. 特定错误类型的附加信息
  if (err.isOperational) {
    // 业务逻辑错误，可添加详细信息
    errorResponse.details = err.details;
  }

  if (err.code) {
    // 错误代码（如数据库错误码）
    errorResponse.code = err.code;
  }

  // 6. 生产环境敏感错误处理
  if (process.env.NODE_ENV === 'production' && !err.isOperational) {
    // 非预期的错误，不暴露详细信息
    errorResponse.message = '服务器遇到意外情况';
    delete errorResponse.stack;
    delete errorResponse.error;
  }

  // 7. 返回错误响应
  res.status(statusCode).json(errorResponse);
});

// 导出app实例，供入口文件启动服务器
module.exports = app;
